GitHub

您所在的位置:网站首页 android auto 最新版 GitHub

GitHub

2024-04-26 07:31| 来源: 网络整理| 查看: 265

《强国助手》说明文档

当前最新版本:V1.0.5

免责声明

《强国助手》为本人Auto.js学习交流的开源非营利项目,仅作为程序员之间相互学习交流之用,使用需严格遵守开源许可协议。严禁用于商业用途,禁止使用《强国助手》进行任何盈利活动。对一切非法使用所产生的后果,本人概不负责。具体声明如下:

1.本项目供程序员日常学习交流使用,不得用于其他任何商业用途。

2.apk软件是本人利用Auto.js打包插件完成的,不包含病毒可放心安装使用。

3.本项目不提倡每天利用脚本软件来刷《学习强国》积分。

4.希望大家正视脚本内容本身,坚持把学习贯彻习近平总书记系列重要讲话精神作为重大政治任务,认真学习党的先进理论与指导思想,请勿利用本软件投机取巧。

5.经过n个账号的两天测试,暂未发现封号风险,理论上Auto.js模仿人的思路对控件进行模拟点击,如果每天一直使用,不保证不会封号。

6.经向专业律师咨询,本声明有效,具有法律效力。

一、文档介绍

本文档的目的是在经过《学习强国》安卓脚本的实战开发后,梳理个人在学习Auto.js过程中的知识点,并对每一个功能进行思路讲解和代码介绍,希望能通过本项目帮助学习Auto.js的人更进一步理解脚本开发步骤和原理。

如果对您有帮助,欢迎您star⭐一下小星星~

仓库内容:

Images文件夹——存放演示图片和视频

强国助手历史版本文件夹——仅作为备份用

强国助手 vX.X.X .apk —— 当前完善的最新版本,脚本打包后封装好的安卓软件应用安装包

学习强国.apk——学习强国v2.10.0版本(截至2020.3.21官方最新版)

Auto.js官方API文档——字面意思

autojs.apk——autojs手机开发IDE(版本:4.1.1 Alpha2)

AutoLearnChina.js —— 当前最新的核心脚本执行文件

Readme.md —— 《强国助手》说明文档

二、产品介绍

本项目是一款基于Auto.js工具开发的安卓脚本应用软件,依靠目前的脚本,最多每日能够获得32积分(除答题以外的所有分值)。

目前软件实现的任务功能包括了以下几点:

1.阅读文章

2.视听学习

3.收藏

4.分享

5.订阅

6.评论

7.本地频道

8.文章学习时长(可选)

9.视听学习时长(可选)

在当日未执行所有任务的情况下,脚本完成任务1-7预计花费7分钟。

脚本完成任务8预计花费12分钟。

脚本完成任务9预计花费18分钟。

未实现的任务功能包括:

1.每日答题

2.每周答题

3.专项答题

4.挑战答题

强国助手APP更新日志 V1.0.5:新增悬浮窗日志显示功能,解决阅读时长任务的bug,新增选项菜单 V1.0.4:解决手机主界面UI字符的屏幕适配问题,解决获取任务列表不稳定的问题 V1.0.3:更新脚本应用的UI效果,增加用户手机息屏检测和屏幕激活,增加看视频时用户是否使用手机流量的检测机制,解决不能首次执行长时阅读任务的BUG V1.0.0:正式发布至GitHub平台 三、如何使用?

版本要求:

1.手机系统:仅支持安卓系统,最好是安卓7.0以上。

2.手机型号:

目前经过测试能正常运行的:

红米K20 Pro(安卓10)、华为nova5pro(安卓10)、华为荣耀20(安卓10)、华为P20 Pro(安卓10)其他机型未知。

其中解决华为手机不能显示脚本执行过程的通知办法:进入手机管家-病毒查杀-风险管控中心-对强国助手解除管控-再打开设置-通知-允许强国助手发送通知

未通过测试的:

oppo A59s(安卓5.1)

3.应用版本:《学习强国》v2.10.0

目前以上版本以通过测试,其他版本机型未知。

使用手册:(建议在Wifi状态下执行脚本软件,因为会涉及到自动观看视频)

1.下载apk软件,安装;

2.关闭《学习强国》软件,打开《强国助手》软件,由强国助手自动启动学习强国;

3.需要打开《强国助手》的无障碍服务和截图功能,到时根据软件提示进行相应操作即可;

4.无需输入任何配置参数,选择是否执行可选任务后,一键运行。

5.在程序运行过程中将手机放到一旁即可,最好不要中途操纵手机,等待程序执行结束,即可查看获得积分或关闭《学习强国》。

附:

如果不小心中途操作手机跳出了学习强国页面,导致脚本执行失败,关闭学习强国软件,重启脚本软件再执行即可。

通常情况下每5秒内会更新脚本执行消息并在屏幕下方显示通知信息(见软件效果静态展示),如果脚本在执行过程中未出现执行过程提示信息但仍在正常执行,请确认手机设置中是否已打开允许强国助手通知(如上华为手机开启通知的解决办法);如果超过20秒学习强国页面未变化,则可能出现了异常,此时关闭学习强国,重启脚本软件再执行即可。

由于脚本并未做学习强国全版本测试,也没有钱做更多的机型适配测试,所以欢迎广大程序员来疯狂测试,程序也存在很多不足,欢迎大家批评指正!望共同进步!

使用效果:

1.软件主页(V1.0.0):

2.使用过程静态展示:

3.使用过程动态展示:(可见Image文件夹中的视频文件)

四、如何进行迭代式增量开发?

参与贡献(内附提交方法):https://github.com/Alivon/Panda-Learning/blob/master/CONTRIBUTING.md

1.了解什么是Auto.js

Auto.js是一个支持无障碍服务的Android平台上的JavaScript IDE,可以编写各种自动化脚本,它主要有以下优点:

无需root:基于无障碍服务; 基于控件:以坐标为基础的按键精灵、脚本精灵很容易出现分辨率问题,而以控件为基础的Auto.js则没有这个问题; 上手简单:使用javascript编写,支持中文变量名; 可打包 :可以将JavaScript打包为apk文件,这一点可以简化用户操作,对上了年纪的用户很重要; 2.配置安装Auto.js和VScode、TotalControl等电脑调试及投屏软件

Auto.js下载与详细介绍:https://github.com/hyb1996/Auto.js/

项目开发的准备工作:https://www.bilibili.com/video/av93396608

Auto.js入门教程:https://space.bilibili.com/21486893

学完了以上3个链接,相信你一定对Auto.js开发有了比较全面基础的理解,在我看来,安卓脚本开发中最难的就是控件的寻找,如果找到了控件,接下来对控件的操作只要学会查API文档,就能应付开发中的大部分情况了。

3.打开本项目的AutoLearnChina.js

在文件底部,你可看到未完成的方法体,它们就是答题模块,本人比较菜,对该部分模块开发还没有什么思路,也希望能得到高人指点,也可共同开发完成。

4.从App应用的一个页面开始,新建文件对该页面上需要完成的功能进行开发。

复制空方法体到一个新文件,或是新建一个函数体,在该新文件中对该方法要完成的功能进行开发,开发完成后复制到原文件中即可。

五、已完成功能的代码思路介绍

教程:

JS入门:https://www.bilibili.com/video/av35958121

控件寻找:https://www.bilibili.com/video/av36724143

控件操作:https://www.bilibili.com/video/av37314451

以下代码均以强国助手V1.0.0脚本应用版本为例,最新版本的代码参见AutoLearnChina.js

1.UI部分

套用模板即可,主要是需要对用户的输入进行传值,需要用户提前开启无障碍服务和截图权限。

"ui"; var form = { isLongRead: false, isLongWatch: false } ui.layout( ); ui.yes_read.on("check",function(check){ if(check){ form.isLongRead= true; } }); ui.no_read.on("check",function(check){ if(check){ form.isLongRead= false; } }); ui.yes_watch.on("check",function(check){ if(check){ form.isLongWatch= true; } }); ui.no_watch.on("check",function(check){ if(check){ form.isLongWatch= false; } }); ui.autoService.on("check", function(checked) { // 用户勾选无障碍服务的选项时,跳转到页面让用户去开启 if(checked && auto.service == null) { app.startActivity({ action: "android.settings.ACCESSIBILITY_SETTINGS" }); } if(!checked && auto.service != null){ auto.service.disableSelf(); } }); // 当用户回到本界面时,resume事件会被触发 ui.emitter.on("resume", function() { // 此时根据无障碍服务的开启情况,同步开关的状态 ui.autoService.checked = auto.service != null; }); ui.start.on("click", function(){ //程序开始运行之前判断无障碍服务 if(auto.service == null) { toastLog("请先开启无障碍服务!"); return; } main(); }); ui.stop.on("click",function(){ threads.shutDownAll(); engines.stopAll(); exit(); toast("已终止执行脚本"); }); 2.Main方法(入口函数) function main() { // 这里写脚本的主逻辑 threads.start(function () { if(!requestScreenCapture()){ toastLog("请先开启截图权限,以执行收藏任务!"); toastLog("运行结束,脚本自动退出..."); exit(); } toastLog("主程序开始运行"); try { //检查无障碍服务是否已经启用,如果没启动,跳转到启动界面,启动后继续执行 // auto.waitFor(); launchApp("学习强国"); waitForPackage("cn.xuexi.android"); sleep(3000); toast("开始执行脚本!") getTaskList(); // 获取任务列表 doUnfinishedTask(); //执行当日未完成的任务 doExtraTask(); back();//回到手机主页 sleep(2000); } catch (error) { log(error) toast("出现异常,请关闭应用重新执行脚本!"); exit(); // 有异常退出,结束脚本 } toastLog("运行结束,脚本自动退出..."); threads.shutDownAll(); engines.stopAll(); exit(); }); } 3.getTaskList(); // 获取任务列表

主要得到当日还未达到满分的任务,将其存入taskInfoList数组。

function getTaskList() { toastLog("执行获取任务列表") // 从主页到我的主页 className("android.widget.TextView").id('comm_head_xuexi_mine').findOne().click(); sleep(2000); // 点击事件在我的积分父控件上 id("user_item_name").text("学习积分").findOne().parent().click() // waitForPackage("cn.xuexi.android") waitForActivity("com.alibaba.lightapp.runtime.activity.CommonWebViewActivity") sleep(3000); toastLog("获取任务列表...") // 获取任务列表 taskInfoList = []; // 重置 className("android.widget.ListView").findOne().children().forEach(function (child) { var list = child.find(className('android.view.View')); log(list) if (list.length > 5) { var title = list.get(2).contentDescription; var content = list.get(4).contentDescription; if (title && content) { var integralContent = content.split('/'); var getIntegral = parseInt(integralContent[0].replace(/[^0-9]/ig, "")); var targetIntegral = parseInt(integralContent[1].replace(/[^0-9]/ig, "")); taskInfoList.push({ title: title, getIntegral: getIntegral, targetIntegral: targetIntegral, }) } } }); if (!taskInfoList.length) { toastLog('获取任务失败!请关闭应用并重启脚本...'); threads.shutDownAll(); engines.stopAll(); exit(); // 有异常退出,结束脚本 } else { toastLog("成功获取任务列表,退到首页"); log(taskInfoList); back();//从“积分”页跳转到“我的” sleep(2000); back();//从“我的”跳转到“首页” sleep(2000); } }; 4.doUnfinishedTask(); //执行当日未完成的任务

这部分也相当于一个入口函数,遍历第2步得到的任务列表的数组,通过条件分支,逐个进入各个方法体完成任务。

function doUnfinishedTask(){ var flag = 0;//判断是否完成所有任务满分的标志 var read_article_flag = 2 //判断阅读文章任务是否已完成,作为参数传入视听学习任务的new_vedio_list用于控件寻找 for(i=0;ifunction readArticle(num,time,isLong){ sleep(1000); toastLog('开始执行阅读文章任务...') //点击要闻 className("android.widget.TextView").text("要闻").findOne().parent().click(); //先看右上角总积分,如果看完某文章,积分没变,说明该文章以前看过,不算有效文章,num不减 var origin_score = id("comm_head_xuexi_score").findOne().getText(); log("origin_score:"+origin_score) //阅读文章 while(num>0){ var newListView = className("android.widget.ListView").depth(20).findOnce(1); log('newListView:'+newListView) if(newListView!=null) { // log('newListView:'+newListView) var newslist = newListView.children(); // log('list.length:'+newslist.length); if (newslist.length > 0) { newslist.forEach(function(item,index){ if(index&&num>0){//index==0时是linearLayout控件,无法点击,也不是子项要闻 sleep(2000); isClick = item.click()//进入新闻内容页 if(isClick) { num--; toastLog("进行模拟阅读"+time+"s...剩余阅读篇数:"+num); // waitForPackage("cn.xuexi.android"); for(var t=1;tfunction learnVideo(num,read_article_flag,time,isLong){ log("read_article_flag:"+read_article_flag); sleep(1000); toastLog('开始执行视听学习任务...'); //进入电视台频道 desc("电视台").id("home_bottom_tab_button_contact").findOne().click(); //先看右上角总积分,如果看完某视频,积分没变,说明该视频以前看过,不算有效视频,num不减 var origin_score = id("comm_head_xuexi_score").findOne().getText(); log("origin_score:"+origin_score) //进入第一频道 className("android.widget.TextView").text("第一频道").findOne().parent().click(); var new_vedio_list = className("android.widget.ListView").depth(20).findOnce(read_article_flag); while(num>0){ new_vedio_list = className("android.widget.ListView").depth(20).findOnce(read_article_flag); log('new_vedio_list:'+new_vedio_list) if(new_vedio_list!=null) { var newslist = new_vedio_list.children(); if (newslist.length > 0) { newslist.forEach(function(item,index){ if(index&&num>0){//index==0时是linearLayout控件,无法点击,也不是子项要闻 sleep(2000); isClick = item.click()//进入视频内容页 if(isClick) { num--; toastLog("进行模拟观看"+time+"s...剩余视听:"+num+"次"); for(var t=1;tfunction share(){ toastLog('开始执行分享任务...'); sleep(1000); //点击要闻 className("android.widget.TextView").text("要闻").findOne().parent().click(); //阅读文章 var newListView = className("android.widget.ListView").depth(20).findOnce(1); if(newListView!=null) { var newslist = newListView.children(); if (newslist.length > 0) { newslist.forEach(function(item,index){ if(index>0&&indexfunction comment(){ toastLog('开始执行发表观点任务...'); sleep(1000); //点击要闻 className("android.widget.TextView").text("要闻").findOne().parent().click(); //阅读文章 var newListView = className("android.widget.ListView").depth(20).findOnce(1); if(newListView!=null) { var newslist = newListView.children(); if (newslist.length > 0) { newslist.forEach(function(item,index){ if(index>0&&indexfunction subscribe(num){ sleep(1000); toastLog('开始执行订阅任务'); // 从主页到我的主页 id("comm_head_xuexi_mine").text("我的").findOne().click(); sleep(2000); //点击订阅控件 id("my_subscribe_tv").text("订阅").findOne().click(); // waitForActivity("android.widget.FrameLayout",200); // log('过来了'); sleep(3000); //在我的订阅里面找到所有订阅号,存起来 var subscribed_accounts = []; //如果没有订阅任何订阅号,那直接点击添加 if(id("no_content_text").exists()){ //点击添加 className("android.widget.TextView").text("添加").findOne().click(); //在添加里面逐一扫描每个订阅号是否在上面的已订阅中,如果没匹配到,则订阅这个公众号,订阅num个即可 accounts_pool = className("android.widget.ListView").depth(13).findOne(); var bottom_flag = 0; while(accounts_pool!=null&&num>0) { sleep(1000); var frameLayoutList = accounts_pool.children(); frameLayoutList.forEach(function(item,index){ if(item.className()=='android.widget.FrameLayout') { var account_name = item.find(className("android.widget.TextView")); if(num>0&&subscribed_accounts.indexOf(account_name[0].text())==-1)//说明数组中不存在这个元素,则订阅他 { num--; subscribed_accounts.push(account_name[0].text()); subscribe_icon = item.find(className("android.widget.LinearLayout"))[1]; // log("subscribe_icon:"+subscribe_icon) toastLog("正在订阅..."); subscribe_icon.click(); sleep(2000); } else if(item.className()=='android.widget.LinearLayout')//遍历到底了 { bottom_flag = 1; return; } } }); if(bottom_flag) { toastLog("强国号都已经订阅完啦..."); break; } accounts_pool.scrollDown(); sleep(2000); accounts_pool = className("android.widget.ListView").depth(13).findOne(); } } else//如果曾经订阅过,那么需要先找到订阅了哪些 { var list_view = className("android.widget.ListView").depth(11).findOne(); // log(list_view) var bottom_flag = 0; while(list_view!=null) { sleep(1000); var frameLayoutList = list_view.children(); // log('frameLayoutList:'+frameLayoutList) frameLayoutList.forEach(function(item,index){ if(item.className()=='android.widget.FrameLayout') { // log(item) var account_name = item.find(className("android.widget.TextView")); // log('已订阅:'+account_name[0].text()) if(subscribed_accounts.indexOf(account_name[0].text())==-1)//说明数组中不存在这个元素 { subscribed_accounts.push(account_name[0].text()); } } else if(item.className()=='android.widget.LinearLayout')//遍历到底了 { bottom_flag = 1; return; } }); if(bottom_flag) { break; } list_view.scrollDown(); sleep(2000); list_view = className("android.widget.ListView").depth(11).findOne(); } log(subscribed_accounts) //点击添加 className("android.widget.TextView").text("添加").findOne().click(); //在添加里面逐一扫描每个订阅号是否在上面的已订阅中,如果没匹配到,则订阅这个公众号,订阅num个即可 accounts_pool = className("android.widget.ListView").depth(13).findOne(); var bottom_flag = 0; while(accounts_pool!=null&&num>0) { sleep(1000); var frameLayoutList = accounts_pool.children(); frameLayoutList.forEach(function(item,index){ if(item.className()=='android.widget.FrameLayout') { var account_name = item.find(className("android.widget.TextView")); if(num>0&&subscribed_accounts.indexOf(account_name[0].text())==-1)//说明数组中不存在这个元素,则订阅他 { num--; subscribed_accounts.push(account_name[0].text()); subscribe_icon = item.find(className("android.widget.LinearLayout"))[1]; // log("subscribe_icon:"+subscribe_icon) toastLog("正在订阅..."); subscribe_icon.click(); sleep(2000); } else if(item.className()=='android.widget.LinearLayout')//遍历到底了 { bottom_flag = 1; return; } } }); if(bottom_flag) { toastLog("强国号都已经订阅完啦..."); break; } accounts_pool.scrollDown(); sleep(2000); accounts_pool = className("android.widget.ListView").depth(13).findOne(); } } toastLog("订阅任务执行结束!d==( ̄▽ ̄*)b"); back();//回到 我的订阅 sleep(1000); back();//回到 我的 sleep(1000); back();//回到学习首页 sleep(1000); }; 8.收藏模块

这部分模块虽然和评论、分享处于同一个详情页面的位置,但是思路和评论分享不同,因为我进入一个页面需要先判断这篇文章是否已经被收藏,而对同一文章进行反复评论分享也能得到积分。所以需要特别注意。

截图功能就是在这里用上的,我需要通过图片来得到收藏小星星控件的中心像素,通过颜色的不同来比较是否收藏过,有人可能会想,订阅部分是否也可以通过图片颜色不同的方式(已订阅是灰色的“√”,未订阅是红色的"+")来区分。事实上会比较麻烦,因为在收藏模块中,其控件在页面的位置是固定的,但是订阅部分是可滑动的。

function collect(){ toastLog('开始执行收藏任务'); sleep(1000); //点击要闻 className("android.widget.TextView").text("要闻").findOne().parent().click(); sleep(1000); //阅读文章 var newListView = className("android.widget.ListView").depth(20).findOnce(1); // log('newListView:'+newListView) var num = 2;//待收藏文章数 while(newListView!=null&&num>0) { // log('newListView:'+newListView) var newslist = newListView.children(); // log('list.length:'+newslist.length); if (newslist.length > 0) { newslist.forEach(function(item,index){ if(index>0&&num>0){//index==0时是linearLayout控件,无法点击,也不是子项要闻 sleep(2000); isClick = item.click()//进入新闻内容页 if(isClick) { toastLog("检测该文章是否收藏..."); sleep(2000); //找到小星星控件 collect_star = className("android.widget.ImageView").depth(10).findOne(); log("collect_star:"+collect_star); //检测小星星是否点亮 //截图取小星星控件的坐标范围 var img = captureScreen(); var star_bounds = collect_star.bounds(); //获取小星星中心的x,y坐标像素 var star_x = star_bounds.centerX(); var star_y = star_bounds.centerY(); // 小星星的中心RGB(255,196,61) var collected_color = colors.rgb(255, 196, 61) var color = images.pixel(img, star_x, star_y); //如果颜色不匹配,说明未收藏 if(!colors.isSimilar(color,collected_color)) { //收藏 toastLog("收藏该文章..."); sleep(1000); collect_star.click(); num--; sleep(1000); } //返回 back(); sleep(2000); } } }); } newListView.scrollDown(); sleep(2000); newListView = className("android.widget.ListView").depth(20).findOnce(1); } toastLog('收藏任务执行结束!d==( ̄▽ ̄*)b') //点击学习控件回到新闻首页 id("home_bottom_tab_button_work").findOne().click(); sleep(1000); };


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3